﻿using Ocelot.Configuration.File;
using SqlSugar;
using SX.BaseService.Repository.Core;
using SX.BaseService.Repository.Entity;
using SX.BaseService.Service.Implement.Microservice.ViewModel;
using SX.BaseService.Service.Interface;
using SX.Core;
using SX.ServiceDiscovery.Abstractions;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace SX.BaseService.Service.Implement.Microservice.Service
{
    public class MicroService:DbContext,IMicroService
    {
        private readonly IServiceDiscovery _serviceDiscovery;
        public MicroService(IServiceDiscovery serviceDiscovery)
        {
            _serviceDiscovery = serviceDiscovery;
        }

        public async Task<IApiResult> AddApiGatewayConfiguration(GatewayConfigurationAddModel input)
        {
            var configInfo = new ApigatewayConfigEntity
            {
                Id = input.Id,
                BaseUrl = input.BaseUrl,
                DownstreamScheme = input.DownstreamScheme,
                GatewayKey = input.GatewayKey,
                HttpHandlerOptions = input.HttpHandlerOptions.ToJson(),
                LoadBalancerOptions = input.LoadBalancerOptions.ToJson(),
                QoSOptions = input.QoSOptions.ToJson(),
                RateLimitOptions =input.RateLimitOptions.ToJson(),
                RequestIdKey = input.RequestIdKey,
                ServiceDiscoveryProvider =input.ServiceDiscoveryProvider.ToJson()
            };
            var res= await Db.Insertable(configInfo).ExecuteCommandAsync();
            return ApiResult.Result(res > 0);
        }

        public async Task<IApiResult> AddApiGatewayReRoute(GatewayReRouteAddModel input)
        {
            var res = 0;
            var rerouteInfo = new ApigatewayReRouteEntity
            {
                AuthenticationOptions = input.AuthenticationOptions.ToJson(),
                CacheOptions =input.FileCacheOptions.ToJson(),
                DelegatingHandlers =input.DelegatingHandlers.ToJson(),
                DownstreamHostAndPorts = input.DownstreamHostAndPorts.ToJson(),
                DownstreamPathTemplate = input.DownstreamPathTemplate,
                Id = input.Id,
                Key = input.Key,
                Priority = input.Priority,
                SecurityOptions = input.SecurityOptions.ToJson(),
                ServiceName = input.ServiceName,
                State = input.State,
                Timeout = input.Timeout,
                UpstreamHost = input.UpstreamHost,
                UpstreamHttpMethod = input.UpstreamHttpMethod.ToJson(),
                UpstreamPathTemplate = input.UpstreamPathTemplate,
                GatewayId = input.GatewayId,
                DownstreamScheme = input.DownstreamScheme,
                HttpHandlerOptions =  input.HttpHandlerOptions.ToJson(),
                LoadBalancerOptions =  input.LoadBalancerOptions.ToJson(),
                QoSOptions =  input.QoSOptions.ToJson(),
                RateLimitOptions =  input.RateLimitOptions.ToJson(),
                RequestIdKey = input.RequestIdKey,
            };
            if (rerouteInfo.Id.NotNull())
            {
                var route = Db.Queryable<ApigatewayReRouteEntity>().First(it => it.UpstreamPathTemplate == rerouteInfo.UpstreamPathTemplate && it.GatewayId == rerouteInfo.GatewayId);
                if (route != null && route.Id != rerouteInfo.Id)
                {
                    return ApiResult.NotOk("上游路由规则已存在");
                }
                res= await Db.Updateable(rerouteInfo).ExecuteCommandAsync();
            }
            else
            {
                // 在网关内已存在
                if (Db.Queryable<ApigatewayReRouteEntity>().Any(it => it.UpstreamPathTemplate == rerouteInfo.UpstreamPathTemplate && it.GatewayId == rerouteInfo.GatewayId))
                    return ApiResult.NotOk("上游路由规则已存在");
               res= await Db.Insertable(rerouteInfo).ExecuteCommandAsync();
            }
            return ApiResult.Result(res > 0);
        }

        public async Task<IApiResult> QueryApiGatewayConfiguration(GatewayConfigurationQueryModel model)
        {
            RefAsync<int> total = 0;
            var queryable = Db.Queryable<ApigatewayConfigEntity>();
            var source = await queryable
                .ToPageListAsync(model.PageIndex, model.PageSize, total);
            PageResult<ApigatewayConfigEntity> result = new PageResult<ApigatewayConfigEntity>()
            {
                Rows = source,
                TotalCount = total
            };
            return ApiResult.Ok(result);
        }

        public async Task<IApiResult> QueryApiGatewayReRouteList(GatewayReRouteQueryModel input)
        {
            RefAsync<int> total = 0;
            var listResult =await Db.Queryable<ApigatewayReRouteEntity>()
                                            .WhereIF(input.GatewayId.NotNull(), it => it.GatewayId == input.GatewayId)
                                            .WhereIF(input.State > -1, it => it.State == input.State)
                                            .ToPageListAsync(input.PageIndex, input.PageSize, total);

            PageResult<ApigatewayReRouteEntity> result = new PageResult<ApigatewayReRouteEntity>()
            {
                Rows = listResult,
                TotalCount = total
            };
            return ApiResult.Ok(result);
        }

        public async Task<IApiResult> SyncApiGatewayConfigurationToConsul(string gatewayId)
        {
            var configInfo =await Db.Queryable<ApigatewayConfigEntity>().FirstAsync(it => it.Id ==gatewayId);
            if (configInfo != null)
            {
                var data = GetGatewayData(gatewayId);
                await _serviceDiscovery.KeyValuePutAsync(configInfo.GatewayKey, data.ToJson());
            }
            return ApiResult.Ok();
        }

        public async Task<IApiResult> SyncApiGatewayConfigurationToRedis(string gatewayId)
        {
            var configInfo = Db.Queryable<ApigatewayConfigEntity>().First(it => it.Id == gatewayId);
            if (configInfo != null)
            {
                var data = GetGatewayData(gatewayId);

                await RedisHelper.SetAsync($"ApiGateway:{configInfo.GatewayKey}", data, TimeSpan.MaxValue);
            }
            return ApiResult.Ok();
        }


        /// <summary>
        /// 查询网关配置数据
        /// </summary>
        /// <param name="gatewayId"></param>
        /// <returns></returns>
        private FileConfiguration GetGatewayData(string gatewayId)
        {
            var fileConfig = new FileConfiguration();
            var configInfo = Db.Queryable<ApigatewayConfigEntity>().First(it => it.Id == gatewayId);
            if (configInfo != null)
            {
                // config
                var fgc = new FileGlobalConfiguration
                {
                    BaseUrl = configInfo.BaseUrl,
                    DownstreamScheme = configInfo.DownstreamScheme,
                    RequestIdKey = configInfo.RequestIdKey,
                };
                if (!string.IsNullOrWhiteSpace(configInfo.HttpHandlerOptions))
                    fgc.HttpHandlerOptions = JsonHelper.DeserializeObject<FileHttpHandlerOptions>(configInfo.HttpHandlerOptions);
                if (!string.IsNullOrWhiteSpace(configInfo.LoadBalancerOptions))
                    fgc.LoadBalancerOptions =JsonHelper.DeserializeObject<FileLoadBalancerOptions>(configInfo.LoadBalancerOptions);
                if (!string.IsNullOrWhiteSpace(configInfo.QoSOptions))
                    fgc.QoSOptions = JsonHelper.DeserializeObject<FileQoSOptions>(configInfo.QoSOptions);
                if (!string.IsNullOrWhiteSpace(configInfo.RateLimitOptions))
                    fgc.RateLimitOptions = JsonHelper.DeserializeObject<FileRateLimitOptions>(configInfo.RateLimitOptions);
                if (!string.IsNullOrWhiteSpace(configInfo.ServiceDiscoveryProvider))
                    fgc.ServiceDiscoveryProvider = JsonHelper.DeserializeObject<FileServiceDiscoveryProvider>(configInfo.ServiceDiscoveryProvider);
                fileConfig.GlobalConfiguration = fgc;
                // reroutes
                var reRouteResult = Db.Queryable<ApigatewayReRouteEntity>().Where(it => it.GatewayId == configInfo.Id && it.State == 1).ToList();
                if (reRouteResult.Count > 0)
                {
                    var reroutelist = new List<FileReRoute>();
                    foreach (var model in reRouteResult)
                    {
                        var m = new FileReRoute()
                        {
                            UpstreamHost = model.UpstreamHost,
                            UpstreamPathTemplate = model.UpstreamPathTemplate,
                            DownstreamPathTemplate = model.DownstreamPathTemplate,
                            DownstreamScheme = model.DownstreamScheme,
                            ServiceName = model.ServiceName,
                            Priority = model.Priority,
                            RequestIdKey = model.RequestIdKey,
                            Key = model.Key,
                            Timeout = model.Timeout,
                        };
                        if (!string.IsNullOrWhiteSpace(model.UpstreamHttpMethod))
                            m.UpstreamHttpMethod = JsonHelper.DeserializeObject<List<string>>(model.UpstreamHttpMethod);
                        if (!string.IsNullOrWhiteSpace(model.DownstreamHostAndPorts))
                            m.DownstreamHostAndPorts = JsonHelper.DeserializeObject<List<FileHostAndPort>>(model.DownstreamHostAndPorts);
                        if (!string.IsNullOrWhiteSpace(model.SecurityOptions))
                            m.SecurityOptions = JsonHelper.DeserializeObject<FileSecurityOptions>(model.SecurityOptions);
                        if (!string.IsNullOrWhiteSpace(model.CacheOptions))
                            m.FileCacheOptions = JsonHelper.DeserializeObject<FileCacheOptions>(model.CacheOptions);
                        if (!string.IsNullOrWhiteSpace(model.HttpHandlerOptions))
                            m.HttpHandlerOptions = JsonHelper.DeserializeObject<FileHttpHandlerOptions>(model.HttpHandlerOptions);
                        if (!string.IsNullOrWhiteSpace(model.AuthenticationOptions))
                            m.AuthenticationOptions = JsonHelper.DeserializeObject<FileAuthenticationOptions>(model.AuthenticationOptions);
                        if (!string.IsNullOrWhiteSpace(model.RateLimitOptions))
                            m.RateLimitOptions = JsonHelper.DeserializeObject<FileRateLimitRule>(model.RateLimitOptions);
                        if (!string.IsNullOrWhiteSpace(model.LoadBalancerOptions))
                            m.LoadBalancerOptions = JsonHelper.DeserializeObject<FileLoadBalancerOptions>(model.LoadBalancerOptions);
                        if (!string.IsNullOrWhiteSpace(model.QoSOptions))
                            m.QoSOptions = JsonHelper.DeserializeObject<FileQoSOptions>(model.QoSOptions);
                        if (!string.IsNullOrWhiteSpace(model.DelegatingHandlers))
                            m.DelegatingHandlers = JsonHelper.DeserializeObject<List<string>>(model.DelegatingHandlers);
                        reroutelist.Add(m);
                    }
                    fileConfig.ReRoutes = reroutelist;
                }
            }
            return fileConfig;
        }
    }
}
